package com.uzhie.jt808.util;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * Created by TangFei on 2018/7/16.
 */
public class ByteUtil {

    private ByteUtil() {
    }

    public static String parseByteString(byte[] bytes, Charset charset) {
        return new String(bytes, charset);
    }

    /**
     * 将整形转换为两位byte数组
     *
     * @param src
     * @return
     */
    public byte[] parseInt2JT808ByteTwo(int src) {
        byte[] temp = new byte[2];
//        temp[0] = (byte) (src >>> 8 & 0xff);
//        temp[1] = (byte) (src & 0xff);
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4);
        byteBuffer.putInt(0,2);
        byteBuffer.position(2);
        byteBuffer.get(temp, 0, 2);
        return temp;
    }

    /**
     * 将字节数组转换成int
     *
     * @param bytes  字节数组
     * @param pos    开始下标
     * @param length 截取长度
     * @return
     * @throws RuntimeException
     */
    public static int parseByteArrayToInt(byte[] bytes, int pos, int length) throws RuntimeException {
        if (pos + length > bytes.length) {
            throw new ArrayIndexOutOfBoundsException("数组下标越界");
        }
        length = length > 4 ? 4 : length;
        ByteBuffer byteBuffer = ByteBuffer.allocate(4);
        for (int i = 0; i < 4 - length; i++) {
            byteBuffer.put((byte) 0X00);
        }
        byteBuffer.put(bytes, pos, length);
        byteBuffer.rewind();
        return byteBuffer.getInt();
    }

    public byte[] objectToByteArray(Serializable obj) {
        if (obj instanceof byte[]) {
            return (byte[]) obj;
        } else if (null != obj) {
            byte[] bytes = null;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                ObjectOutputStream oos = new ObjectOutputStream(bos);
                oos.writeObject(obj);
                oos.flush();
                bytes = bos.toByteArray();
                oos.close();
                bos.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return bytes;
        } else {
            return (new byte[0]);
        }
    }

    public <T> T byteArrayToObject(byte[] bytes) {
        T obj = null;
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bis);
            obj = (T) ois.readObject();
            ois.close();
            bis.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        return obj;
    }

    /**
     * 转换校验码 （从消息头开始，同后一字节异或，直到校验码前一个字节）
     *
     * @param data 要转换的byte数组
     * @return
     */
    public static int parseCheckCode(byte[] data, int end) {
        int cs = 0 & 0xFF;
        for (int i = 0; i < end; i++) {
            cs ^= (data[i] & 0XFF);
        }
        return cs;
    }

    public static byte[] concatAll(byte[] first, byte[]... rest) {
        int totalLength = first.length;
        for (byte[] array : rest) {
            if (array != null) {
                totalLength += array.length;
            }
        }
        byte[] result = Arrays.copyOf(first, totalLength);
        int offset = first.length;
        for (byte[] array : rest) {
            if (array != null) {
                System.arraycopy(array, 0, result, offset, array.length);
                offset += array.length;
            }
        }
        return result;
    }

    public static byte[] integerTo1Bytes(int value) {
        byte[] result = new byte[1];
        result[0] = (byte) (value & 0xFF);
        return result;
    }

    public static byte[] integerTo2Bytes(int value) {
        byte[] result = new byte[2];
        result[0] = (byte) ((value >>> 8) & 0xFF);
        result[1] = (byte) (value & 0xFF);
        return result;
    }

    /**
     * 获取十六进制的字符串形式
     *
     * @param bytes  byte[]
     * @param pos    开始下标
     * @param length 长度
     * @return
     */
    public String byteArrayToString(byte[] bytes, int pos, int length) {
        byte[] temp = new byte[length];
        System.arraycopy(bytes, pos, temp, 0, length);
        return BCDByteArrayToString(temp);
    }

    /**
     * 获取十六进制的字符串形式
     *
     * @param bytes byte数组
     * @return
     */
    public static String BCDByteArrayToString(byte[] bytes) {
        // 1byte = 2位hex
        StringBuilder temp = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            // 高四位
            temp.append((bytes[i] & 0xF0) >>> 4);
            // 低四位
            temp.append(bytes[i] & 0x0F);
        }
        return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp.toString().substring(1) : temp.toString();
    }

    public static byte[] stringToBCDByteArray(String str) {
        // 奇数,前补零
        if ((str.length() & 0x1) == 1) {
            str = "0" + str;
        }
        byte ret[] = new byte[str.length() / 2];
        byte bs[] = str.getBytes();
        for (int i = 0; i < ret.length; i++) {
            byte high = ascII2BCD(bs[2 * i]);
            byte low = ascII2BCD(bs[2 * i + 1]);
            // TODO 只遮罩BCD低四位
            ret[i] = (byte) ((high << 4) | low);
        }
        return ret;
    }

    private static byte ascII2BCD(byte asc) {
        if ((asc >= '0') && (asc <= '9'))
            return (byte) (asc - '0');
        else if ((asc >= 'A') && (asc <= 'F'))
            return (byte) (asc - 'A' + 10);
        else if ((asc >= 'a') && (asc <= 'f'))
            return (byte) (asc - 'a' + 10);
        else
            return (byte) (asc - 48);
    }

    /**
     * 把16进制字符串转换成字节数组
     * @param hex
     * @return byte[]
     */
    public static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static int toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }

}
